package com.library.books.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.library.books.domain.Books;
import com.library.books.domain.BooksCopy;
import com.library.books.domain.Increment;
import com.library.books.domain.Print;
import com.library.books.domain.dto.BooksCopyIncrementDto;
import com.library.books.domain.vo.BooksCopyTempVo;
import com.library.books.domain.vo.BooksJoinBooksCopy;
import com.library.books.domain.vo.UserCopyRememberInfo;
import com.library.books.domain.vo.print.PrintRequireInfoData;
import com.library.books.mapper.BooksCopyMapper;
import com.library.books.service.*;
import com.library.common.core.domain.entity.SysUser;
import com.library.common.enums.BooksCopyStatus;
import com.library.common.enums.IncrementStatus;
import com.library.common.enums.OperateTerraceType;
import com.library.common.enums.PrintStatus;
import com.library.common.exception.RfidUseException;
import com.library.common.gdxx.domain.req.BookInfoPushReq;
import com.library.common.gdxx.domain.resp.GDXXResponse;
import com.library.common.gdxx.push.InternalPush;
import com.library.common.utils.SecurityUtils;
import com.library.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

/**
 * 书籍副本Service业务层处理
 *
 * @author hb
 * @date 2024-10-14
 */
@Slf4j
@Service
public class BooksCopyServiceImpl extends ServiceImpl<BooksCopyMapper, BooksCopy> implements IBooksCopyService
{

    @Resource
    private IBooksCopyService bookCopyService;

    @Resource
    private IBooksService booksService;

    @Resource
    IIncrementService incrementService;

    @Resource
    IPrintService printService;

    @Resource
    IGDXXPushService igdxxPushService;

    @Resource
    InternalPush internalPush;

    /**
     * 查询书籍副本列表
     *
     *
     * @param booksCopy 书籍副本
     * @return 书籍副本
     */
    @Override
    public List<BooksCopy> selectBooksCopyList(BooksCopy booksCopy) {
        return baseMapper.selectBooksCopyList(booksCopy);
    }

    /**
     * 查询书籍拼接书籍副本数据
     *
     * @param booksJoinBooksCopy 书籍拼接书籍副本实体类
     * @return 书籍拼接书籍副本集合
     */
    @Override
    public BooksJoinBooksCopy selectBooksCopyJoinBooks(BooksJoinBooksCopy booksJoinBooksCopy) {
        return baseMapper.selectBooksCopyJoinBooks(booksJoinBooksCopy);
    }

    /**
     * 查询书籍拼接书籍副本列表
     *
     * @param booksJoinBooksCopy 书籍拼接书籍副本实体类
     * @return 书籍拼接书籍副本集合
     */
    @Override
    public List<BooksJoinBooksCopy> selectBooksCopyJoinBooksList(BooksJoinBooksCopy booksJoinBooksCopy) {
        return baseMapper.selectBooksCopyJoinBooksList(booksJoinBooksCopy);
    }

    /**
     * 查询书籍拼接书籍副本列表
     *  - 分页数据
     * @param booksJoinBooksCopy 书籍拼接书籍副本实体类
     * @return 书籍拼接书籍副本集合
     */
    @Override
    public List<BooksJoinBooksCopy> selectBooksCopyJoinBooksListByPage(BooksJoinBooksCopy booksJoinBooksCopy) {
        LambdaQueryWrapper<Books> select = Wrappers.lambdaQuery(Books.class).select(Books::getBooksId);
        if(StringUtils.isNotEmpty(booksJoinBooksCopy.getBooksCnType())) {
            select.eq(Books::getBooksCnType,booksJoinBooksCopy.getBooksCnType());
        }
        if(StringUtils.isNotEmpty(booksJoinBooksCopy.getBooksName())) {
            select.like(Books::getBooksName,booksJoinBooksCopy.getBooksName());
        }
        List<Object> booksIds = booksService.listObjs(select);
        return null;
    }

    /**
     * 查询书籍拼接书籍副本回收列表
     *
     * @param booksJoinBooksCopy 书籍拼接书籍副本实体类
     * @return 书籍拼接书籍副本集合
     */
    @Override
    public List<BooksJoinBooksCopy> selectBooksCopyJoinBooksRecoveryList(BooksJoinBooksCopy booksJoinBooksCopy) {
        return baseMapper.selectBooksCopyJoinBooksRecoveryList(booksJoinBooksCopy);
    }

    /**
     * 软删除
     *
     * @param ids id
     * @return 结果
     */
    @Override
    public boolean softDeletion(Long[] ids) {
        QueryWrapper<BooksCopy> booksCopyQueryWrapper = new QueryWrapper<>();
        booksCopyQueryWrapper.in("books_copy_id", Arrays.asList(ids));
        List<BooksCopy> booksCopyList = new ArrayList<>();
        for (Long id : ids) {
            BooksCopy booksCopy = new BooksCopy();
            booksCopy.setBooksCopyId(id);
            booksCopy.setBooksCopySoft(1L);
            booksCopyList.add(booksCopy);
        }
        return bookCopyService.updateBatchById(booksCopyList);
    }

    /**
     * 恢复书籍副本
     *
     * @param ids id
     * @return 结果
     */
    @Override
    public boolean recoveryBooksCopy(Long[] ids) {
        // 查询数据是否存在
        List<BooksCopy> db = list(Wrappers.lambdaQuery(BooksCopy.class).select(BooksCopy::getBooksCopyRfid).in(BooksCopy::getBooksCopyId, ids));
        if(db != null ) {
            // 被删除掉的数据rfid是否已经存在
            List<String> rfids = db.stream().map(BooksCopy::getBooksCopyRfid).collect(Collectors.toList());
            List<Object> list = listObjs(Wrappers.lambdaQuery(BooksCopy.class).select(BooksCopy::getBooksCopyRfid).in(BooksCopy::getBooksCopyRfid, rfids).eq(BooksCopy::getBooksCopySoft, "0"));
            if(list.size() > 0) {
                throw new RfidUseException(list);
            }

            QueryWrapper<BooksCopy> booksCopyQueryWrapper = new QueryWrapper<>();
            booksCopyQueryWrapper.in("books_copy_id", Arrays.asList(ids));
            List<BooksCopy> booksCopyList = new ArrayList<>();
            for (Long id : ids) {
                BooksCopy booksCopy = new BooksCopy();
                booksCopy.setBooksCopyId(id);
                booksCopy.setBooksCopySoft(0L);
                booksCopyList.add(booksCopy);
            }
            return bookCopyService.updateBatchById(booksCopyList);
        }
        return Boolean.FALSE;
    }

    /**
     * 生成副本模板数据
     *  - 主要是处理索书号（国图书分类 + 自增）的 自增数据保持唯一
     * @param booksCopy 必要的参数
     * @return 模板数据
     * @deprecated 读写器自动读取了
     */
    @Deprecated
    @Override
    @Transactional(rollbackFor = Exception.class , isolation = Isolation.READ_COMMITTED)
    public List<BooksCopyTempVo> generateTemplate(BooksCopyIncrementDto booksCopy) {
        int retry = 3 ;
        String booksCnType = "CnType:" + booksCopy.getBooksCnType();
        Long booksCopyNum = booksCopy.getBooksCopyNum();
        while(retry != 0) {
            Increment one = incrementService.getOne(Wrappers.lambdaQuery(Increment.class)
                .eq(Increment::getUse, "0")
                .eq(Increment::getKey, booksCnType)
            );
            if(one == null) {
                one = new Increment().setKey(booksCnType).setUse("1").setIncrement(booksCopyNum);
                incrementService.save(one);
            }else if("1".equals(one.getUse())) {
                retry--;
                continue;
            }else {
                boolean use = incrementService.update(Wrappers.lambdaUpdate(Increment.class)
                    .set(Increment::getUse, "1")
                    .eq(Increment::getId, one.getId())
                    .eq(Increment::getKey, one.getKey())
                );
                if(! use) {
                    retry--;
                    continue;
                }
            }
            // 处理数据
            List<BooksCopyTempVo> booksCopys = new ArrayList<>();
            for(long i = one.getIncrement() ; i < one.getIncrement() + booksCopyNum ; i++ ) {
                booksCopys.add(new BooksCopyTempVo()
                    .setBooksId(booksCopy.getBooksId())
                    .setBookShelfId(booksCopy.getBookShelfId())
                    .setBooksCopyRuleId(booksCopy.getBooksCopyRuleId())
                    .setBooksCopyStatus(booksCopy.getBooksCopyStatus())
                    .setBooksCopyLicense(booksCopy.getBooksCnType() + "/" + i)
                );
            }
            return booksCopys;
        }
        throw new RuntimeException("请稍等");
    }

    /**
     * 批量新增副本数据
     *  - 新增对应待打印数据
     *  - 加上同步了 (锁)
     * @param booksCopyList 打印列表
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class , isolation = Isolation.READ_COMMITTED)
    public UserCopyRememberInfo batchInsertBooksCopy(List<BooksCopy> booksCopyList) {

        try{
            Thread.sleep(200);
        }catch (Exception e){
            e.printStackTrace();
        }
        // 计数器
        AtomicLong atomicCnType = new AtomicLong();

        // 计数器key前缀
        String incrPrefix = "CnType:";

        // getBooksCopyCnType ==> 纯净的类型 K837.125.38=536 而不是 getBooksCopyLicense ==> K837.125.38=536/种次号
        Map<String, List<BooksCopy>> licenseMap = booksCopyList.stream().collect(Collectors.groupingBy(BooksCopy::getBooksCopyCnType));
        licenseMap.forEach((k, v) -> {
            // 索书号类型，提取第一个分类即可（A123、B111.23）
            String smallTypeStr = k.toUpperCase();
            String smallTypeKey = incrPrefix + smallTypeStr;

            // 查询当前中国图书法分类自增对象
            List<Increment> incrementList = incrementService.list(Wrappers.lambdaQuery(Increment.class)
                    .in(Increment::getKey,smallTypeKey)
            );
            Increment small = incrementList.stream().filter(b -> smallTypeKey.equals(b.getKey())).findFirst().orElse(null);

            // 索书号类型自增 锁定
            if(small == null) {
                small = new Increment(null, smallTypeKey, k , IncrementStatus.USE.getCode(),"0", 1L);
                incrementService.save(small);
            }else if(IncrementStatus.USE.equals(small.getUse())) {
                log.error("索书号自增key：{} 正在被使用",small.getKey());
                throw new RuntimeException("请稍等");
            }
            atomicCnType.set(small.getIncrement());

            // 添加自增值
            for (BooksCopy copy : v) {
                // 副本数据由ISO文件导入时会存在（那是个必填的 字段标识符 905）
                String[] split = copy.getBooksCopyLicense().split("/");
                if(split.length < 2) {
                    long smallIncrement = atomicCnType.getAndIncrement();
                    copy.setBooksCopyLicense(split[0] + "/" + smallIncrement);
                    copy.setBooksCopyLicensePos(smallIncrement);
                }else {
                    // 和数据库对比（导入的索书号比数据库大则更新成导入索书号）
                    if(copy.getBooksCopyLicensePos() >= atomicCnType.get()) {
                        // +1 是先获取再++，因为填充所以补充代码中++的部分
                        atomicCnType.set(copy.getBooksCopyLicensePos() + 1);
                    }
                }
            }
            // 更新未使用
            incrementService.update(Wrappers.lambdaUpdate(Increment.class)
                    .set(Increment::getUse,IncrementStatus.UNUSE.getCode())
                    .set(Increment::getIncrement,atomicCnType.get())
                    .eq(Increment::getKey,smallTypeKey)
            );
        });
        // 当前用户添加打印数据之前
        UserCopyRememberInfo remember = new UserCopyRememberInfo();
        remember.setBefore(count(Wrappers.lambdaQuery(BooksCopy.class).eq(BooksCopy::getBooksCopySoft, 0)));
        if(saveBatch(booksCopyList)) {

            // 新增打印记录数据
            String userNumber = SecurityUtils.getLoginUser().getUser().getUserNumber();
            List<Print> prints = booksCopyList.stream().map(bc -> {
                Print print = new Print();
                print.setBooksCopyId(bc.getBooksCopyId());
                print.setPrintStatus(PrintStatus.NO.getCode());
                print.setOperateNumber(userNumber);
                print.setOperateTerrace(OperateTerraceType.DESK.getCode());
                return print;
            }).collect(Collectors.toList());
            if(printService.saveBatch(prints)) {
                // 打印记录新数据添加后
                remember.setAfter(count(Wrappers.lambdaQuery(BooksCopy.class).eq(BooksCopy::getBooksCopySoft, 0)));
                // 当前用户未打印副本次数
                remember.setNoPrint(printService.selectPrintCount(PrintStatus.NO));
                return remember;
            }
        }
        throw new RuntimeException("副本添加失败");
    }

    @Override
    public Long selectBooksCopyCount() {
        return baseMapper.selectBooksCopyCount();
    }

}
